package com.smart.lab.utils.net;

/**
 * Created by liuyan on 2019/2/28.
 */

import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.smart.lab.utils.net.listener.HttpResponseListener;
import com.smart.lab.utils.net.listener.UploadListener;
import com.smart.lab.view.common.intercept.AddCookiesInterceptor;
import com.smart.lab.view.common.intercept.ReceivedCookiesInterceptor;

import java.io.File;
import java.io.FileNotFoundException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.Retrofit.Builder;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Body;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.HeaderMap;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.PartMap;
import retrofit2.http.QueryMap;
import retrofit2.http.Url;

public final class HttpHelper {
    private static final String TAG = HttpHelper.class.getSimpleName();

    private static volatile WeakReference<HttpHelper> sInstance;
    private final Retrofit mRetrofit;
    private static String sBaseUrl;

    public static void setBaseUrl(String baseUrl) {
        sBaseUrl = baseUrl;
    }

    public static String getBaseUrl() {
        return sBaseUrl;
    }

    private static OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(new AddCookiesInterceptor()) //这部分
            .addInterceptor(new ReceivedCookiesInterceptor()) //这部分
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();

    private HttpHelper() {
        Builder builder = new Builder();
        if (TextUtils.isEmpty(getBaseUrl())) {
            throw new NullPointerException("init(Context,httpBaseUrl)：httpBaseUrl is not null");
        } else {
            this.mRetrofit = builder.baseUrl(getBaseUrl())
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
    }

    public static HttpHelper getInstance() {
        if (sInstance == null || sInstance.get() == null) {
            Class var0 = HttpHelper.class;
            synchronized (HttpHelper.class) {
                if (sInstance == null || sInstance.get() == null) {
                    sInstance = new WeakReference(new HttpHelper());
                }
            }
        }

        return (HttpHelper) sInstance.get();
    }

    public static <T> Call getAsync(String apiUrl, @HeaderMap Map<String, Object> headers, Map<String, Object> paramMap, HttpResponseListener<T> httpResponseListener) {
        if (paramMap == null) {
            paramMap = new HashMap();
        }

        if (headers == null) {
            headers = new HashMap();
        }

        HttpService httpService = (HttpService) getInstance().mRetrofit.create(HttpService.class);
        Call call = httpService.get(apiUrl, (Map) headers, (Map) paramMap);
        parseNetData(call, httpResponseListener);
        return call;
    }

    public static <T> Call postAsync(String apiUrl, @HeaderMap Map<String, Object> headers, Map<String, Object> paramMap, HttpResponseListener<T> httpResponseListener) {
        if (paramMap == null) {
            paramMap = new HashMap();
        }

        if (headers == null) {
            headers = new HashMap();
        }

        HttpService httpService = (HttpService) getInstance().mRetrofit.create(HttpService.class);
        Call call = httpService.post(apiUrl, (Map) headers, (Map) paramMap);
        parseNetData(call, httpResponseListener);
        return call;
    }


    public static <T> Call postAsyncWithBody(String apiUrl, String body, final HttpResponseListener<T> httpResponseListener) {

        HttpService httpService = (HttpService) getInstance().mRetrofit.create(HttpService.class);

        // 设置请求类型
        MediaType mediaType = MediaType.parse("application/json;charset=UTF-8");
        final RequestBody requestBody = RequestBody.create(mediaType, body);
        Call call = httpService.post1(apiUrl, requestBody);
        parseNetData(call, httpResponseListener);
        return call;
    }

    public static Call upload(Request request, final UploadListener uploadListener) {
        if (request.getUploadFiles() == null || !((File) request.getUploadFiles().get(0)).exists()) {
            (new FileNotFoundException("file does not exist(文件不存在)")).printStackTrace();
        }

        HashMap requestBodyMap = new HashMap();
        RequestBody requestBody = RequestBody.create(request.getMediaType(), (File) request.getUploadFiles().get(0));
        requestBodyMap.put("file\"; filename=\"" + ((File) request.getUploadFiles().get(0)).getName(), requestBody);
        String httpUrl = request.getApiUlr().trim();
        String tempUrl = httpUrl.substring(0, httpUrl.length() - 1);
        String baseUrl = tempUrl.substring(0, tempUrl.lastIndexOf(File.separator) + 1);
        if (L.isDebug) {
            L.i("httpUrl:" + httpUrl);
            L.i("tempUrl:" + tempUrl);
            L.i("baseUrl:" + baseUrl);
            L.i("apiUrl:" + httpUrl.substring(baseUrl.length()));
        }

        HttpService service = (HttpService) getInstance().mRetrofit.create(HttpService.class);
        Call model = null;
        model = service.postUploadWithParamsAndHeader(httpUrl.substring(baseUrl.length()), "file", requestBodyMap, request.getParamsMap(), request.getHeaderMap());
        model.enqueue(new Callback<ResponseBody>() {
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                Log.d("onResponse", "onResponse");
                try {
                    String e = ((ResponseBody) ((response.body() == null) ? response.errorBody() : response.body())).string();
                    if (L.isDebug) {
                        L.i("response data:" + e);
                    }

                    if (!String.class.equals(uploadListener.getType())) {
                        Gson gson = new Gson();
                        Object t = gson.fromJson(e, uploadListener.getType());
                        uploadListener.onResponse(t);
                    } else {
                        uploadListener.onResponse(e);
                    }
                } catch (Exception var6) {
                    if (L.isDebug) {
                        L.e("Http Exception:", var6);
                    }

                    uploadListener.onFailure(call, var6);
                }
            }

            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.d("onFailure", "onResponse");
                uploadListener.onFailure(call, t);
            }
        });
        return model;
    }

    public static <T> Call uploadMultiPart(String url, Map<String, String> map, List<File> fileList, HttpResponseListener<T> httpResponseListener) {
        Map<String, RequestBody> params = new HashMap<>();
        //以下参数是伪代码，参数需要换成自己服务器支持的

        if (map != null && map.size() > 0) {
            Iterator iter = map.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry) iter.next();
                Object key = entry.getKey();
                Object val = entry.getValue();
                params.put((String) key, convertToRequestBody((String) val));
            }
        }

        List<MultipartBody.Part> partList = filesToMultipartBodyParts(fileList);

        HttpService service = (HttpService) getInstance().mRetrofit.create(HttpService.class);
        Call model = service.postImagesAndParams(url, params, partList);
        parseNetData(model, httpResponseListener);
        return model;
    }


    private static <T> void parseNetData(Call<ResponseBody> call, final HttpResponseListener<T> httpResponseListener) {
        call.enqueue(new Callback<ResponseBody>() {
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    String e = ((ResponseBody) ((response.body() == null) ? response.errorBody() : response.body())).string();
                    if (L.isDebug) {
                        L.i("response data:" + e);
                    }

                    if (!String.class.equals(httpResponseListener.getType())) {
                        Gson gson = new Gson();
                        Object t = gson.fromJson(e, httpResponseListener.getType());
                        httpResponseListener.onResponse((T) t);
                    } else {
                        httpResponseListener.onResponse((T) e);
                    }
                } catch (Exception var6) {
                    if (L.isDebug) {
                        L.e("Http Exception:", var6);
                    }

                    httpResponseListener.onFailure(call, var6);
                }

            }

            public void onFailure(Call<ResponseBody> call, Throwable t) {
                httpResponseListener.onFailure(call, t);
            }
        });
    }

    public interface HttpService<T> {
        @GET
        Call<ResponseBody> get(@Url String var1, @HeaderMap Map<String, String> var2, @QueryMap Map<String, Object> var3);

        @FormUrlEncoded
        @POST
        Call<ResponseBody> post(@Url String var1, @HeaderMap Map<String, String> var2, @FieldMap Map<String, Object> var3);

        @POST
        Call<ResponseBody> post1(@Url String var1, @Body RequestBody var2);

        @Multipart
        @POST
        Call<String> postUpload(@Url String var1, @Part("uploadDes") String var2, @PartMap Map<String, RequestBody> var3);

        @Multipart
        @POST
        Call<ResponseBody> postUploadWithParamsAndHeader(@Url String var1, @Part("uploadDes") String var2, @PartMap Map<String, RequestBody> var3, @QueryMap Map<String, Object> var4, @HeaderMap Map<String, String> var5);

        @Multipart
        @GET
        Call<String> getUpload(@Url String var1, @Part("uploadDes") String var2, @PartMap Map<String, RequestBody> var3);

        //具体业务-上传文字和多张图片
        @Multipart
        @POST
        Call<ResponseBody> postImagesAndParams(@Url String var1, @PartMap Map<String, RequestBody> map, @Part List<MultipartBody.Part> imageFile);

    }

    private static List<MultipartBody.Part> filesToMultipartBodyParts(List<File> files) {
        List<MultipartBody.Part> parts = new ArrayList<>(files.size());
        for (File file : files) {
            RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
            MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), requestBody);
            parts.add(part);
        }
        return parts;
    }

    private static RequestBody convertToRequestBody(String param) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), param);
        return requestBody;
    }
}
